#include "command.h"
#include "head.h"
#include "login.h"
#include "taskQueue.h"
#include "tcp.h"
#include "timeWheel.h"
#include <mysql/mysql_com.h>
#include <pthread.h>
#include <time.h>
int exitPipeFd[2];
// 主人通过信号控制工人全部退出
void handler(int num){
    write(exitPipeFd[1],"1",1);
}
void init_openssl() {
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
}
/* Usage:  */
//int getHash(char *usrName,char *hash,int usrNameLen){
//    SHA_CTX ctx;
//    SHA1_Init(&ctx);
//    SHA1_Update(&ctx,usrName,usrNameLen);
//    unsigned char md[20]={0};
//    SHA1_Final(md,&ctx);
//    char sha1str[41]={0};
//    for(int i=0;i<20;++i){
//        char temp[3]={0};
//        sprintf(temp,"%02X",md[i]);
//        strcat(sha1str,temp);
//    }
//    strcpy(hash,sha1str);
//    return 0;
//}
int main(){
    init_openssl();
    pipe(exitPipeFd);
    if(fork()){
        printf("pid=%d\n",getpid());
        close(exitPipeFd[0]);
        /* signal(SIGUSR1,handler); */
        while(1){
            sleep(1);
        }
        wait(NULL);
        printf("All workers exit!\n");
        exit(0);
    }

    threadPool_t threadPool;
    threadPool_t *pThreadPool=&threadPool;
    getParaMeter(&pThreadPool->configUsrInfo);
    initThreadPool(pThreadPool,atoi(pThreadPool->configUsrInfo.workerNum));
    /* initThreadPool(pThreadPool,4); */
    // lastReadySet.arry[j][0]  存放netFd
    // lastReadySet.arry[j][1]  0 
    timeWheel_t timeWheel[30];
    int hash[1024][2];
    for(int i=0;i<1024;++i){
        hash[i][0]=0;
        hash[i][1]=0;
    }
    for(int i=0;i<30;++i){
        timeWheel[i].lastReadySet.curIdx=1;
        for(int j=0;j<20;++j){
            timeWheel[i].lastReadySet.arry[j][0]=0;
            timeWheel[i].lastReadySet.arry[j][1]=0;
        }
    }

    pthread_mutex_lock(&pThreadPool->mutex);
    MYSQL *mysql=NULL;
    MySQLCon(&mysql,&pThreadPool->configUsrInfo);
    pthread_mutex_unlock(&pThreadPool->mutex);
    makeWorker(pThreadPool);
    int sockFd=initTcp(pThreadPool->configUsrInfo.addr,pThreadPool->configUsrInfo.port);
    /* int sockFd=initTcp(argv1,argv2); */
    int epollFd=epoll_create(10);
    epollAdd(epollFd,exitPipeFd[0]);
    epollAdd(epollFd,sockFd);
    struct epoll_event readySet[1024];
    int curIdx=0;
    int idx=0;
    while(1){
        int readyNum=epoll_wait(epollFd,readySet,1024,1000);
        // 集合中的第0行第0列存放第一个要覆盖的下标
        // 集合中的第0行第1列存放最后一个要覆盖的下标
        /* printf("idx=%d,readyNum=%d\n",idx,readyNum); */
        checkAndClean(epollFd,idx,timeWheel);
        int isDel=timeWheel[idx].lastReadySet.arry[0][0];
        for(int i=0;i<readyNum;++i){
            if(readySet[i].data.fd==sockFd){
                //新客户端连接，将netfd加入监听
                int netFd=accept(sockFd,NULL,NULL);
                pThreadPool->usrInfo[curIdx].netFd=netFd;
                addToTimeWheel(timeWheel,&isDel,idx,netFd,hash);
                epollAdd(epollFd,netFd);
                ++curIdx;
            }
            else if(readySet[i].data.fd==exitPipeFd[0]){
                // 监听到退出信号
                printf("exit\n");
                pthread_mutex_lock(&pThreadPool->mutex);
                pThreadPool->exitFlag=1;
                pthread_cond_broadcast(&pThreadPool->cond);
                pthread_mutex_unlock(&pThreadPool->mutex);
                for(int j=0;j<pThreadPool->tidArr.workerNum;++j){
                    pthread_join(pThreadPool->tidArr.pWorker[j],NULL);
                }
                printf("all exit\n");
                exit(0);
            }
            else{  
                // 处理短命令
                printf("处理短命令\n");
                int netFd=readySet[i].data.fd;    
                for(int i=0;i<curIdx;++i){
                    if(netFd==pThreadPool->usrInfo[i].netFd){
                        train_t train;
                        int cmdExRet=commandExcute(&pThreadPool->usrInfo[i],&train,pThreadPool,mysql);
                        printf("主人线程处理完成\n");
                        if(cmdExRet==1){
                            printf("关闭netfd=%d\n",netFd);
                            epollDel(epollFd,netFd);
                            close(netFd);
                            int lastTimeIdx=hash[netFd][0];
                            int lastSetIdx=hash[netFd][1];
                            timeWheel[lastTimeIdx].lastReadySet.arry[lastSetIdx][0]=0;
                            hash[netFd][0]=0;
                            hash[netFd][1]=0;
                        }
                        else if(cmdExRet==2){
                            // 旧客户端新线程连接，进行token验证
                            int lastTimeIdx=hash[netFd][0];
                            int lastSetIdx=hash[netFd][1];
                            timeWheel[lastTimeIdx].lastReadySet.arry[lastSetIdx][0]=0;
                            hash[netFd][0]=0;
                            hash[netFd][1]=0;
                            commandType type=TOK;
                            int nameLen;
                            char name[16]={0};
                            char token[41];
                            recv(netFd,&nameLen,sizeof(int),0);
                            recv(netFd,name,nameLen,0);
                            recv(netFd,token,41,0);
                            printf("tk=%s\n",token);
                            char LocalToken[41];
                            int n=0;
                            for(;n<curIdx;++n){
                                if(strcmp(name,pThreadPool->usrInfo[n].usrName)==0 && netFd != pThreadPool->usrInfo[n].netFd){
                                    break;
                                }
                            }
                            getHash(name,LocalToken,nameLen);
                            if(strcmp(LocalToken,token)==0){
                                send(netFd,&type,sizeof(type),0);
                                int masterNetFd=pThreadPool->usrInfo[n].netFd;
                                pThreadPool->usrInfo[n].netFd=netFd;
                                printf("客户端传输线程fd=%d\n",pThreadPool->usrInfo[n].netFd);
                                pthread_mutex_lock(&pThreadPool->mutex);
                                enQueue(&pThreadPool->taskQueue,pThreadPool->usrInfo[n]);
                                pthread_cond_broadcast(&pThreadPool->cond);
                                pthread_mutex_unlock(&pThreadPool->mutex);
                                pThreadPool->usrInfo[n].netFd=masterNetFd;
                                printf("客户端主线程fd=%d\n",pThreadPool->usrInfo[n].netFd);
                                epollDel(epollFd,netFd);
                                return 0;
                            }
                            else{
                                printf("未通过验证\n");
                                type=ERROR;
                                send(netFd,&type,sizeof(type),0);
                                return 1;
                            }
                        }
                        // 时间轮更新
                        else{
                            printf("更新时间\n");
                            addToTimeWheel(timeWheel,&isDel,idx,netFd,hash);
                        }
                    }
                }
            }
        }
        ++idx;
        if(idx==30){
            idx=0;
        }
    }
    return 0;
}

